1

前言:其实js动画跟CSS-DOM结合的挺紧密的,都是用js函数实现一段时间内重复设置元素的样式就形成了动画,其中涉及到大量的用DOM获取元素样式操作,所以可以先看一下CSS-DOM那篇文章,这次总结一下js中的动画,这一篇是基础知识总结,只用到了setTimeout函数,还有两个定时器函数下篇文章总结,最后要实现一个纯js轮播图Demo,好的,黑喂狗

------------------ 你瞅啥? -------------------------

1.一个Demo

首先想让一个元素移动要先设置一个元素,假设我们现在有一标签:<p id="message">Hello World!!!</p>,我们可以在js代码中设置它的初始位置:position:absolute,设置它距离left和right的距离,如下代码

        function positionMessage(){
        //检测与判断
        if(!document.getElementById){
            return false;
        }
        if(!document.getElementById("message")){
            return false;
        }
        //获取元素的标签
        var elem = document.getElementById("message");
        //设置元素的位置
        elem.style.position = "absolute";
        elem.style.left = "50px";
        elem.style.top = "100px";
    }

接下来我们介绍一个延迟执行函数,setTimeout(),它接受两个参数,第一个参数时字符串,内容是将要执行的那个函数名字;第二个参数是一个数值,以毫秒为单位设定需要经过多长时间后才开始执行第一个参数里面的函数。所以有个这个函数,我们可以写一个不断改变位置的函数moveMessage(),然后把它传递给setTimeout()函数。如下代码:

    function moveMessage(){
        if(!document.getElementById){
            return false;
        }
        if(!document.getElementById("message")){
            return false;
        }
        var elem = document.getElementById("message");
        var xpos = parseInt(elem.style.left);
        var ypos = parseInt(elem.style.top);
        if(xpos ==200&&ypos == 100){
            return true;
        }
        if(xpos  < 200){
            xpos++;
        }
        if(xpos > 200){
            xpos--;
        }
        if(ypos < 100){
            ypos++;
        }
        if(ypos > 100){
            ypos--;
        }
        elem.style.left = xpos + "px";
        elem.style.top = ypos + "px";
        movement = setTimeout("moveMessage()",10);
    }

1.首先获取原始的left和position值,由于涉及到很多计算,所以将字符串转换为数。
2.进行一些判断,将目标位置设置在left在200px,top不变,也就是将其向右水平移动。然后进行逻辑判断:如果到达目标位置,就返回true,函数执行完毕。
3.如果没有到达位置,则不断将数值加1,如果超过设定位置则减1.
4.最后在moveMessage()函数内部设置setTimeout()函数,即在moveMessage()函数一次执行结束后,就每隔10毫秒再次调用这个函数,即在刚开始每隔10毫秒向右移动1px,直到到达设定地点函数return true结束整个函数。

最后要在页面加载完成后调用这个函数,所以要用到老朋友addLoadEvent()函数,如下代码:

    function addLoadEvent(func){
        var oldonload = window.onload;
        if(typeof window.onoad != 'function'){
            window.onload = func;
        }else{
            window.onload = function(){
                oldonload();
                func(); 
            }
        }
    }

最后在页面加载完成时执行moveMessage()函数:

    addLoadEvent(PositionMessage);

2.抽象

刚才创建的moveMessage()函数中有很多信息都是硬编码在函数中,这个函数的灵活性和适用范围就小,所以将一些具体的东西抽象出来,则这个函数就更加便于复用。
现在我们创建一个moveElement()函数,看下面代码:

       //首先为这个函数传进几个参数
        //@elementID:打算移动的元素的ID
        //@final_x:该元素目的地距左边的位置
        //@final_y:该元素目的地距上边的位置
        //@interval:该元素两次移动之间的停顿时间
        function moveElement(elementID,final_x,final_y,interval){
            //进行检测和判断
            if(!document.getElementById){
                return false;
            }
            if(!document.getElementById(elementID)){
                return false;
            }
            var elem = document.getElementById(elementID);  //参数没有引号
            var xpos =parseInt(elem.style.left);
            var ypos = parseInt(elem.style.top);
            if(xpos == final_x && ypos == final_y){
                return true;
            } 
            if(xpos  < final_x){
                xpos++;
            }
            if(xpos > final_x){
                xpos--;
            }
            if(ypos < final_y){
                ypos++;
            }
            if(ypos > final_y){
                ypos--;
            }
            elem.style.left = xpos + "px";
            elem.style.top = ypos + "px";
            //由于这次moveElement()函数是带参数的,所以再次调用这个函数要写成下面一行。
            //movement = setTimeout("moveElement('"+elementID+"',"+final_x+","+final_y+","+interval+")",10);
            //但是这么写不简洁,所以可以复制给一个变量
            var repeat = "moveElement('"+elementID+"',"+final_x+","+final_y+","+interval+")";
            movement = setTimeout(repeat,interval);
        }

直到现在我终于明白为什么要做一次判断减减了,因为抽象之后,可能传入的参数会让元素向相反的方向移动,这样就写可以让函数无论向哪个方向移动都可以了。

抽象之后,可以在positionMessage的最后直接调用moveElement函数,如下代码:

        function positionMessage(){
        //检测与判断
        if(!document.getElementById){
            return false;
        }
        if(!document.getElementById("message")){
            return false;
        }
        //获取元素的标签
        var elem = document.getElementById("message");
        //设置元素的位置
        elem.style.position = "absolute";
        elem.style.left = "50px";
        elem.style.top = "100px";
        
        //调用移动函数,可以随意改变值,以实现不用的动画效果
        moveElement("message",200,100,10);
    }

3.另一个抽象

//函数animation传入四个参数,
//@ele:要进行动画的DOM对象
//@attr:要改变的属性
//@ from , to 属性值从哪个值到哪个值

var animation = function(ele, attr, from, to){
    var distance = Math.abs(to - from);
    var stepLength = distance/100;
    var sign = (to - from)/distance;  //代表方向
    var offset = 0;
    //step函数是每触发的时候改变一下属性值
    var step = function(){
        var temOffset = offset + stepLength;
        if(temOffset < distance){
            ele.style[attr] = from + temOffset*sign + 'px';
            offset = temOffset;
        }else{
            ele.style[attr] = to + 'px';
            clearInterval(intervalID);
        }
    }
    ele.style[attr] = from + 'px';
    
    //先调用定时器,每10毫秒触发一次step函数
    var intervalID = setTimeout(step,10);
}

以上是网易前端微专业老师给出的抽象代码,还介绍了另外两个函数,将在下一篇中介绍。
另外,完整源代码中没用这个抽象函数。

4.完整源代码

<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8">
    <title>example</title>

</head>

<body>
    <p id="message">Hello World!!!</p>

    <script>
        function positionMessage(){
            if(!document.getElementById){
                return false;
            }
            if(!document.getElementById("message")){
                return false;
            }
            var elem = document.getElementById("message");
            elem.style.position = "absolute";
            elem.style.left = "50px";
            elem.style.top = "100px";
            moveElement("message",125,25,20);

        }

        function moveElement(elementID,final_x,final_y,interval){
            if(!document.getElementById){
                return false;
            }
            if(!document.getElementById(elementID)){
                return false;
            }
            var elem = document.getElementById(elementID);
            var xpos =parseInt(elem.style.left);
            var ypos = parseInt(elem.style.top);
            if(xpos == final_x && ypos == final_y){
                return true;
            } 
            if(xpos  < final_x){
                xpos++;
            }
            if(xpos > final_x){
                xpos--;
            }
            if(ypos < final_y){
                ypos++;
            }
            if(ypos > final_y){
                ypos--;
            }
            elem.style.left = xpos + "px";
            elem.style.top = ypos + "px";
            var repeat = "moveElement('"+elementID+"',"+final_x+","+final_y+","+interval+")";
            movement = setTimeout(repeat,interval);
        }

        //页面加载函数
        function addLoadEvent(func){
            var oldonload = window.onload;
            if(typeof window.onload != 'function'){
                window.onload = func;
            }else{
                window.onload = function(){
                    oldonload();
                    func();
                }
            }
        }

        //页面加载时执行这个函数
        addLoadEvent(positionMessage);

    </script>
</body>

</html>

yangdepp
446 声望21 粉丝

只有那些疯狂的人才能引起我的兴趣,那些人疯狂地生活,疯狂地表达,同时对一切事物心怀渴望,他们毫无倦意,不屑于陈词滥调,只是燃烧,燃烧,燃烧。